home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 189_01 / roff.c < prev    next >
Text File  |  1985-08-19  |  11KB  |  535 lines

  1. /* text formatter transcribed from the book Software Tools */
  2.  
  3. #include <ctype.h>
  4. #include <stdio.h>
  5.  
  6. #define PAGEWIDTH 60    /* default page width */
  7. #define PAGELEN    66        /* default page length */
  8. #define MAXLINE 255
  9. #define PAGECHAR '#'    /* page number escape char */
  10. #define HUGE 32700
  11. #define YES    1
  12. #define NO    0
  13. #define OK    1
  14.  
  15. #define max(a,b) (a >= b) ? a : b
  16. #define min(a,b) (a <= b) ? a : b
  17. #define abs(x)   (x >= 0) ? x : -x
  18.  
  19. int    fill = YES,                /* in fill mode if YES */
  20.        lsval = 1,                /* current line spacing */
  21.        inval = 0,                /* current indent; >= 0 */
  22.        rmval = PAGEWIDTH,            /* current right margin */
  23.        tival = 0,                /* current temporary indent */
  24.        ceval = 0,                /* number of lines to center */
  25.        ulval = 0,                /* number of lines to underline */
  26.        curpag = 0,                /* current output page number */
  27.        newpag = 1,                /* next output page number */
  28.        lineno = 0,                /* next line to be printed */
  29.        plval = PAGELEN,        /* page length in lines */
  30.        m1val = 2,                /* top margin, including header */
  31.        m2val = 3,                /* margin after header */
  32.        m3val = 2,                /* margin after last text line */
  33.        m4val = 3,                /* bottom margin, including footer */
  34.        bottom,                    /* last live line on page: */
  35.                             /*  = plval - m3val - m4val */
  36.        outp,                    /* index into outbuf */
  37.        outw,                    /* width of text in outbuf */
  38.        outwds,                    /* number of words in outbuf */
  39.      dir;                    /* directions flag */
  40.  
  41. char header[MAXLINE],          /* top of page title */
  42.      footer[MAXLINE],          /* bottom of page title */
  43.      outbuf[MAXLINE];        /* lines to be filled go here */
  44.  
  45. main(argc,argv)
  46. int argc;
  47. char *argv[];
  48. {
  49.     register i;
  50.  
  51.     init();
  52.  
  53.     for (i = 1; i < argc; ++i)
  54.         if (freopen(argv[i],"r",stdin) == NULL)
  55.             fprintf(stderr,"can't open %s\n",argv[i]);
  56.         else
  57.             roff();
  58. }
  59.  
  60.  
  61. /* initialize header, footer, and line-count invariant */
  62.  
  63. init()
  64. {
  65.     bottom = plval - m3val - m4val; /* invariant */
  66.     strcpy(header,"\n");
  67.     strcpy(footer,"\n");
  68. }
  69.  
  70.  
  71. /* format current file */
  72.  
  73. roff()
  74. {
  75.     char inbuf[MAXLINE];
  76.  
  77.     while (fgets(inbuf,MAXLINE-1,stdin) != NULL)
  78.         if (inbuf[0] == '.')
  79.             command(inbuf);
  80.         else
  81.             text(inbuf);
  82.  
  83.     if (lineno > 0)
  84.         space(HUGE);
  85. }
  86.  
  87.  
  88. /* perform formatting command */
  89.  
  90. command(buf)
  91. char *buf;
  92. {
  93.     int val, spval;
  94.     char *argtyp;
  95.  
  96.     val = getval(buf,argtyp);
  97.     if (lookup(buf,"bp"))
  98.     {
  99.         if (lineno > 0)
  100.             space(HUGE);
  101.         set(&curpag,val,argtyp,curpag+1,-HUGE,HUGE);
  102.         newpag = curpag;
  103.     }
  104.     else if (lookup(buf,"br"))
  105.         brk();
  106.     else if (lookup(buf,"ce"))
  107.     {
  108.         brk();
  109.         set(&ceval,val,argtyp,1,0,HUGE);
  110.     }
  111.     else if (lookup(buf,"fi"))
  112.     {
  113.         brk();
  114.         fill = YES;
  115.     }
  116.     else if (lookup(buf,"fo"))
  117.          strcpy(footer,buf+3);
  118.     else if (lookup(buf,"he"))
  119.         strcpy(header,buf+3);
  120.     else if (lookup(buf,"in"))
  121.     {
  122.         set(&inval,val,argtyp,0,0,rmval-1);
  123.         tival = inval;
  124.     }
  125.     else if (lookup(buf,"ls"))
  126.         set(&lsval,val,argtyp,1,1,HUGE);
  127.     else if (lookup(buf,"nf"))
  128.     {
  129.         brk();
  130.         fill = NO;
  131.     }
  132.     else if (lookup(buf,"pl"))
  133.     {
  134.         set(&plval,val,argtyp,PAGELEN,m1val+m2val+m3val+m4val+1,HUGE);
  135.         bottom=plval-m3val-m4val;
  136.     }
  137.     else if (lookup(buf,"rm"))
  138.         set(&rmval,val,argtyp,PAGEWIDTH,tival+1,HUGE);
  139.     else if (lookup(buf,"sp"))
  140.     {
  141.         set(&spval,val,argtyp,1,0,HUGE);
  142.         space(spval);
  143.     }
  144.     else if (lookup(buf,"ti"))
  145.     {
  146.         brk();
  147.         set(&tival,val,argtyp,0,0,rmval);
  148.     }
  149.     else if (lookup(buf,"ul"))
  150.         set(&ulval,val,argtyp,0,1,HUGE);
  151.     else
  152.         return;    /* ignore unknown commands */
  153. }
  154.  
  155.  
  156. /* lookup routine for commands */
  157.  
  158. lookup(buf,string)
  159. char *buf, *string;
  160. {
  161.     return (buf[1] == string[0]) && (buf[2] == string[1]);
  162. }
  163.  
  164.  
  165. /* evaluate optional numeric argument */
  166.  
  167. getval(buf,argtyp)
  168. char *buf, *argtyp;
  169. {
  170.     int i;
  171.  
  172.     i = 3;
  173.     /* ..find argument.. */
  174.     while (buf[i] == ' ' || buf[i] == '\t')
  175.         ++i;
  176.     *argtyp = buf[i];
  177.     if (*argtyp == '+' || *argtyp=='-')
  178.         i++;
  179.  
  180.     return(atoi(buf+i));
  181. }
  182.  
  183.  
  184. /* set parameter and check range */
  185.  
  186. set(param,val,argtyp,defval,minval,maxval)
  187. int *param,val,defval,minval,maxval;
  188. char *argtyp;
  189. {
  190.     if (*argtyp == '\n')
  191.         *param = defval;
  192.     else if (*argtyp == '+')
  193.         *param += val;
  194.     else if (*argtyp == '-')
  195.         *param -= val;
  196.     else
  197.         *param = val;
  198.  
  199.     *param = min(*param,maxval);
  200.     *param = max(*param,minval);
  201. }
  202.  
  203. /* process text lines */
  204.  
  205. text(inbuf)
  206. char *inbuf;
  207. {
  208.     char wrdbuf[MAXLINE];
  209.     int i;
  210.  
  211.     if (isspace(*inbuf))
  212.         leadbl(inbuf);    /* go left. set tival */
  213.  
  214.     if (ulval > 0)
  215.     {
  216.         underl(inbuf,wrdbuf,MAXLINE);
  217.         ulval--;
  218.     }
  219.     if (ceval > 0)
  220.     {
  221.         center(inbuf);
  222.         put(inbuf);
  223.         ceval--;
  224.     }
  225.     else if (*inbuf == '\n')
  226.         put(inbuf);
  227.     else if (fill == NO)
  228.         put(inbuf);
  229.     else
  230.     {
  231.         i = 0;
  232.         while (getwrd(inbuf,&i,wrdbuf) > 0)
  233.             putwrd(wrdbuf);
  234.     }
  235. }
  236.  
  237.  
  238. /* delete leading blanks.  Set tival */
  239.  
  240. leadbl(buf)
  241. char *buf;
  242. {
  243.     register i,j;
  244.  
  245.     brk();
  246.  
  247.     /* find first non blank */
  248.     i = 0;
  249.     while (buf[i] == ' ')
  250.         i++;
  251.  
  252.     if (buf[i] != '\n')
  253.         tival += i;
  254.  
  255.     /* move line to left */
  256.     j = 0;
  257.     while ((buf[j++] = buf[i++]) != '\0') ;
  258. }
  259.  
  260.  
  261. /* put out line with proper spacing and indenting */
  262.  
  263. put(buf)
  264. char *buf;
  265. {
  266.     register i;
  267.  
  268.     if ((lineno == 0) || (lineno > bottom))
  269.         phead();
  270.  
  271.     i = 1;
  272.     while (i++ <= tival)
  273.         putchar(' ');
  274.  
  275.     tival = inval;    /* tival good for one line only */
  276.     fputs(buf,stdout);
  277.     skip(min(lsval-1,bottom-lineno));
  278.     lineno += lsval;
  279.     if (lineno > bottom)
  280.         pfoot();
  281. }
  282.  
  283.  
  284. /* put out page header */
  285.  
  286. phead()
  287. {
  288.     curpag = newpag++;
  289.     if (m1val > 0)
  290.     {
  291.         skip(m1val-1);
  292.         puttl(header,curpag);
  293.     }
  294.     skip(m2val);
  295.     lineno = m1val+m2val+1;
  296. }
  297.  
  298.  
  299. /* put out page footer */
  300.  
  301. pfoot()
  302. {
  303.     skip(m3val);
  304.     if (m4val > 0)
  305.     {
  306.         puttl(footer,curpag);
  307.         skip(m4val-1);
  308.     }
  309. }
  310.  
  311.  
  312. /* put out title line with optional page number */
  313.  
  314. puttl(buf,pageno)
  315. char *buf;
  316. int pageno;
  317. {
  318.     register i;
  319.  
  320.     for (i = 0; buf[i] != '\n' && buf[i] != '\0'; i++)
  321.         if (buf[i] == PAGECHAR)
  322.             printf("%*d",1,pageno);
  323.         else
  324.             putchar(buf[i]);
  325.     putchar('\n');
  326. }
  327.  
  328.  
  329. /* space n lines or to bottom of page */
  330.  
  331. space(n)
  332. int n;
  333. {
  334.     brk();
  335.     if (lineno > bottom)
  336.         return;
  337.  
  338.     if (lineno == 0)
  339.         phead();
  340.  
  341.     skip(min(n,bottom+1-lineno));
  342.     lineno += n;
  343.     if (lineno > bottom)
  344.         pfoot();
  345. }
  346.  
  347.  
  348. /* output n blank lines */
  349.  
  350. skip(n)
  351. register n;
  352. {
  353.     while ((n--) > 0)
  354.         putchar('\n');
  355. }
  356.  
  357.  
  358. /* get non-blank word from in[i] into out.
  359.  * increment *i.
  360.  */
  361.  
  362. getwrd(in,ii,out)
  363. char *in, *out;
  364. int *ii;
  365. {
  366.     register i, j;
  367.  
  368.     i = *ii;
  369.     while ((in[i]  == ' ') || (in[i] == '\t'))
  370.         i++;
  371.  
  372.     j = 0;
  373.     while ( (in[i] != '\0') && !isspace(in[i]) )
  374.         out[j++] = in[i++];
  375.  
  376.     out[j] = '\0';
  377.     *ii = i;        /* return index in ii */
  378.     return(j);    /* return length of word */
  379. }
  380.  
  381.  
  382. /* put a word in outbuf; includes margin justification */
  383.  
  384. putwrd(wrdbuf)
  385. char *wrdbuf;
  386. {
  387.     int last, llval, w, nextra;
  388.  
  389.     w = width(wrdbuf);
  390.     /* new end of wrdbuf */
  391.     last = strlen(wrdbuf)+outp+1;
  392.     llval = rmval-tival;
  393.